/**	
 * float4.js
 * 
 * Implements a 4-component vector type.
 * 
 * @author A.Weissflog
 * 
 * (C) 2010 A.Weissflog
 */

/**
 * The default constructor, all component are set to 0.0.
 */
function Float4()
{
	this.x = 0.0;
	this.y = 0.0;
	this.z = 0.0;
	this.w = 0.0;
}

/**
 * Construct Float4 from values.
 * 
 * @param {Number} _x
 * @param {Number} _y
 * @param {Number} _z
 * @param {Number} _w
 */
Float4.FromValues = function(_x, _y, _z, _w)
{
	var v = new Float4;
	v.x = _x;
	v.y = _y;
	v.z = _z;
	v.w = _w;
	return v;
}

/**
 * Construct Float4 from other Float4.
 * 
 * @param {Float4} rhs
 */
Float4.FromFloat4 = function(rhs)
{
	var v = new Float4;
	v.x = rhs.x;
	v.y = rhs.y;
	v.z = rhs.z;
	v.w = rhs.w;
	return v;
}

/**
 * Compare content of 2 Float4's with tolerance.
 * 
 * @param {Float4} f0
 * @param {Float4} f1
 * @param {Number} tol
 */
Float4.Equal = function(f0, f1, tol)
{
    return (Math.abs(f0.x - f1.x) <= tol) &&
	       (Math.abs(f0.y - f1.y) <= tol) &&
		   (Math.abs(f0.z - f1.z) <= tol) &&
		   (Math.abs(f0.w - f1.w) <= tol);	
}

/**
 * Convert content to string.
 * 
 * @return {String}
 */
Float4.prototype.AsString = function()
{
	return "{x: " + this.x + ", y:" + this.y + ", z:" + this.z + ", w:" + this.w + "}";
}

/**
 * Set component values.
 * 
 * @param {Number} _x
 * @param {Number} _y
 * @param {Number} _z
 * @param {Number} _w
 */
Float4.prototype.Set = function(_x, _y, _z, _w)
{
	this.x = _x;
	this.y = _y;
	this.z = _z;
	this.w = _w;
}

/**
 * In-place component-wise add operation.
 * 
 * @param {Float4} rhs
 */
Float4.prototype.Add = function(rhs)
{
	this.x += rhs.x;
	this.y += rhs.y;
	this.z += rhs.z;
	this.w += rhs.w;
}

/**
 * Add 2 Float4's component-wise.
 * 
 * @param {Float4} v0
 * @param {Float4} v1
 * @return {Float4}
 */
Float4.Add = function(v0, v1)
{
	var v = Float4.FromFloat4(v0);
	v.Add(v1);
	return v;	
}

/**
 * In-place component-wise subtraction
 *
 * @param {Float4} rhs
 */
Float4.prototype.Sub = function(rhs)
{
	this.x -= rhs.x;
	this.y -= rhs.y;
	this.z -= rhs.z;
	this.w -= rhs.w;
}

/**
 * Subtract 2 Float4 vectors (v0 - v1)
 * 
 * @param {Float4} v0
 * @param {Float4} v1
 * @return {Floa4}
 */
Float4.Sub = function(v0, v1)
{
	var v = Float4.FromFloat4(v0);
	v.Sub(v1);
	return v;
}

/**
 * Returns 3-component dot product of 2 Float4.
 *
 * @param {Float4} v0
 * @param {Float4} v1
 * @return {Number}
 */
Float4.Dot3 = function(v0, v1)
{
	return v0.x * v1.x + v0.y * v1.y + v0.z * v1.z;	
}

/**
 * Returns the length of a Float4 vector.
 * 
 * @return {Number}
 */
Float4.prototype.Length = function()
{
	return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
}

/**
 * Returns the squared length of a Float4 vector.
 * 
 * @return {Number}
 */
Float4.prototype.LengthSq = function()
{
	return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
}

/**
 * In-place reciprocal of Float4 components.
 */
Float4.prototype.Reciprocal = function()
{
	this.x = 1.0 / this.x;
	this.y = 1.0 / this.y;
	this.z = 1.0 / this.z;
	this.w = 1.0 / this.w;
}

/**
 * In-place per-component multiply.
 * 
 * @param {Float4} rhs
 */
Float4.prototype.Mul = function(rhs)
{
	this.x *= rhs.x;
	this.y *= rhs.y;
	this.z *= rhs.z;
	this.w *= rhs.w;
}

/**
 * Per-component multiply of 2 Float4's
 * 
 * @param {Float4} v0
 * @param {Float4} v1
 * @return {Float4}
 */
Float4.Mul = function(v0, v1)
{
	var v = Float4.FromFloat4(v0);
	v.Mul(v1);
	return v;
}

/**
 * Inplace per-component absolute value.
 *  
 * @param {Float4} rhs
 */
Float4.prototype.Abs = function(rhs)
{
	this.x = Math.abs(this.x);
	this.y = Math.abs(this.y);
	this.z = Math.abs(this.z);
	this.w = Math.abs(this.w);
}

/**
 * Inplace 3-component cross product.
 * 
 * @param {Float4} rhs
 */
Float4.prototype.Cross3 = function(rhs)
{
	var _x = this.y * rhs.z - this.z * rhs.y;
	var _y = this.z * rhs.x - this.x * rhs.z;
	var _z = this.x * rhs.y - this.y * rhs.x;
 	this.x = _x;
	this.y = _y;
	this.z = _z;
	this.w = 0.0;
}

/**
 * Cross3 product of 2 Float4's.
 *
 * @param {Float4} v0
 * @param {Float4} v1
 * @return {Float4}
 */
Float4.Cross3 = function(v0, v1)
{
	var v = Float4.FromFloat4(v0);
	v.Cross3(v1);
	return v;
}

/**
 * Inplace linear interpolation.
 * 
 * @param {Float4} rhs
 * @param {Number} s
 */
Float4.prototype.Lerp = function(rhs, s)
{
	this.x = this.x + ((rhs.x - this.x) * s);
	this.y = this.y + ((rhs.y - this.y) * s);
	this.z = this.z + ((rhs.z - this.z) * s);
	this.w = this.w + ((rhs.w - this.w) * s);
}

/**
 * Linear interpolation between 2 Float4 vectors.
 * 
 * @param {Float4} v0
 * @param {Float4} v1
 * @param {Number} s
 * @return {Float4}
 */
Float4.Lerp = function(v0, v1, s)
{
	var v = Float4.FromFloat4(v0);
	v.Lerp(v1, s);
	return v;
}

/**
 * Inplace per-component maximize.
 *
 * @param {Float4} rhs 
 */
Float4.prototype.Max = function(rhs)
{
	this.x = Math.max(this.x, rhs.x);
	this.y = Math.max(this.y, rhs.y);
	this.z = Math.max(this.z, rhs.z);
	this.w = Math.max(this.w, rhs.w);
}

/**
 * Return per-component maximized Float4.
 * 
 * @param {Object} v0
 * @param {Object} v1
 * @return {Float4}
 */
Float4.Max = function(v0, v1)
{
	var v = Float4.FromFloat4(v0);
	v.Max(v1);
	return v;
}

/**
 * Inplace per-component minimize.
 *
 * @param {Float4} rhs 
 */
Float4.prototype.Min = function(rhs)
{
	this.x = Math.min(this.x, rhs.x);
	this.y = Math.min(this.y, rhs.y);
	this.z = Math.min(this.z, rhs.z);
	this.w = Math.min(this.w, rhs.w);
} 

/**
 * Return per-component minimzed Float4.
 * 
 * @param {Object} v0
 * @param {Object} v1
 * @return {Float4}
 */
Float4.Min = function(v0, v1)
{
	var v = Float4.FromFloat4(v0);
	v.Min(v1);
	return v;
}

/**
 * Inplace normalize Float4 vector.
 */
Float4.prototype.Normalize = function()
{
	var l = this.Length();
	if (l > 0.0)
	{
		var oneDivL = 1.0 / l;
		this.x *= oneDivL;
		this.y *= oneDivL;
		this.z *= oneDivL;
		this.w *= oneDivL;
	}
}

/**
 * Get normalized Float4 vector.
 * 
 * @param {Float4} rhs
 * @return {Float4}
 */
Float4.Normalize = function(rhs)
{
	var v = Float4.FromFloat4(rhs);
	v.Normalize();
	return v;
}
